package ggaviator

import (
	"sync"
	"wzgames/internal/model/aviatorp"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/statement"
	"wzgames/internal/secure"
	"wzgames/internal/services/games"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/utils/byteutil"
)

// 小飞机Marker

type AviatorMarker struct {
	games.Marker
	mu sync.Mutex

	serverSeed string
	nextSeed   string

	avBetU *gamep.BetUser // 投注用户信息
	// 投注位 1
	bet1    *aviatorp.BetNote  // 发往avtower
	betObj1 *statement.PlayBet // 投注信息
	avBet1  *statement.AviatorBetInfo
	// 投注位 2
	bet2    *aviatorp.BetNote // 发往avtower
	betObj2 *statement.PlayBet
	avBet2  *statement.AviatorBetInfo

	autoMap map[int64]*AutoBets // 自动CashOut缓存

	// 当前轮次标记
	play1 int64
	play2 int64
}

func NewAviatorMarker() games.IMarkerService {
	m := &AviatorMarker{
		autoMap: make(map[int64]*AutoBets),
	}
	return m
}

func (mk *AviatorMarker) InitServerSeed(serverSeed, nextServerSeed string) {
	mk.serverSeed = serverSeed
	mk.nextSeed = nextServerSeed
}

func (mk *AviatorMarker) NextServerSeed256() string {
	return secure.Sha256Hex(byteutil.StringToSliceByte(mk.nextSeed))
}

func (mk *AviatorMarker) RefreshSeed(nextServerSeed string) {
	mk.serverSeed = mk.nextSeed
	mk.nextSeed = nextServerSeed
}

func (mk *AviatorMarker) ServerSeed() string {
	return mk.serverSeed
}

func (mk *AviatorMarker) SetAvBetU(betU *gamep.BetUser) {
	mk.avBetU = betU
}

func (mk *AviatorMarker) GetAvBetU() *gamep.BetUser {
	return mk.avBetU
}

// CheckIdxPlay 防止同一轮次 同一投注位 重复操作
func (mk *AviatorMarker) CheckIdxPlay(idx string, currRoundId int64) bool {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if idx == BetIdx1 {
		if mk.play1 < currRoundId {
			mk.play1 = currRoundId
			return true
		}
	} else {
		if mk.play2 < currRoundId {
			mk.play2 = currRoundId
			return true
		}
	}
	return false
}

// ClearIdxPlay 清除标记
func (mk *AviatorMarker) ClearIdxPlay(idx string) {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if idx == BetIdx1 {
		mk.play1 = 0
	} else {
		mk.play2 = 0
	}
}

// CheckBet 判断是否可以投注
func (mk *AviatorMarker) CheckBet(bt *aviatorp.BetNote, betObj *statement.PlayBet, avBet *statement.AviatorBetInfo) bool {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if bt.BetId == BetIdx1 {
		// 对应投注位 判断轮次合法
		if mk.bet1 != nil && mk.bet1.RoundId > bt.RoundId {
			mk.play1 = 0
			return false
		} else {
			mk.bet1 = bt
			mk.betObj1 = betObj
			mk.avBet1 = avBet
			mk.checkAutoCashOut(bt, betObj, avBet) // 判断是否有auto CashOut设置
			return true
		}
	} else {
		if mk.bet2 != nil && mk.bet2.RoundId > bt.RoundId {
			mk.play2 = 0
			return false
		} else {
			mk.bet2 = bt
			mk.betObj2 = betObj
			mk.avBet2 = avBet
			mk.checkAutoCashOut(bt, betObj, avBet)
			return true
		}
	}
}

// checkAutoCashOut 判断是否有auto CashOut设置
func (mk *AviatorMarker) checkAutoCashOut(bt *aviatorp.BetNote, betObj *statement.PlayBet, avBet *statement.AviatorBetInfo) {
	if avBet.AutoMulti <= 1.0 {
		return
	}
	autoRnd, ok := mk.autoMap[bt.RoundId]
	if !ok {
		mk.autoMap[bt.RoundId] = &AutoBets{
			Num:  0,
			Bets: make(map[string]*AutoBetInfo),
		}
		autoRnd = mk.autoMap[bt.RoundId]
	}
	// 缓存
	autoRnd.Num++
	autoRnd.Bets[bt.BetId] = &AutoBetInfo{
		RoundId:   bt.RoundId,
		AutoMulti: avBet.AutoMulti,
		BetIdx:    bt.BetId,
		AvtMarker: mk,
		BetN:      bt,
		BetObj:    betObj,
		AvBet:     avBet,
	}
}

// GetAutoCashOut 获取自动CashOut信息
func (mk *AviatorMarker) GetAutoCashOut(roundId int64, betId string) *AutoBetInfo {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	bets, ok := mk.autoMap[roundId]
	if ok {
		if bInfo, ok1 := bets.Bets[betId]; ok1 {
			if bInfo.AvBet != nil {
				if bInfo.AvBet.Cancel || bInfo.AvBet.CashOut {
					return nil
				}
				bInfo.AvBet.CashOut = true
				bInfo.AvBet.AutoCashOut = true
			}
			return bInfo
		}
	}

	return nil
}

// RemoveAutoCashOut 移除自动CashOut信息
func (mk *AviatorMarker) RemoveAutoCashOut(roundId int64, betId string) {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	mk.removeAutoCashOut(roundId, betId)
}

func (mk *AviatorMarker) removeAutoCashOut(roundId int64, betId string) {
	bets, ok := mk.autoMap[roundId]
	if ok {
		if bets.Num == 0 {
			delete(mk.autoMap, roundId)
			return
		}
		_, ok1 := bets.Bets[betId]
		if ok1 {
			delete(bets.Bets, betId)
			bets.Num--

			if bets.Num == 0 {
				delete(mk.autoMap, roundId)
			}
		}
	}
}

// CheckAutoCashOutPoint 小飞机播报过程检查自动CashOut设置
func (mk *AviatorMarker) CheckAutoCashOutPoint(tb *games.GameTable, airCraft *AirCraft, roundId int64, multi, maxMulti float64) {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	bets, ok := mk.autoMap[roundId]
	if !ok || bets.Num <= 0 {
		return
	}
	for betIdx, v := range bets.Bets { // 遍历有自动CashOut的
		if v.CheckPoint {
			continue
		}
		if v.AutoMulti > maxMulti { // 设置的期望值过高，直接移除
			mk.removeAutoCashOut(roundId, betIdx)
			continue
		}
		if v.AutoMulti <= multi { // auto cashOut
			v.CheckPoint = true // 标记已处理
			// 发往Player actor进行异步处理
			actorservice.Send(tb.Player.Pid(), &games.AutoCashOutCheckPoint{
				Tb:       tb,
				BetIdx:   betIdx,
				RoundId:  roundId,
				Multi:    multi,
				MaxMulti: maxMulti,
			})
			airCraft.PlayAction(v.BetObj.BetId, roundId, 2)
		}
	}
}

func (mk *AviatorMarker) ClearAutoCashOut(roundId int64) {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	bets, ok := mk.autoMap[roundId]
	if ok {
		for idx, _ := range bets.Bets {
			delete(bets.Bets, idx)
		}
		delete(mk.autoMap, roundId)
	}
}

func (mk *AviatorMarker) GetBetNode(betId string) (*aviatorp.BetNote, *statement.PlayBet, *statement.AviatorBetInfo) {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if betId == BetIdx1 {
		return mk.bet1, mk.betObj1, mk.avBet1
	}
	return mk.bet2, mk.betObj2, mk.avBet2
}

// CheckCancel 判断是否可以取消投注
func (mk *AviatorMarker) CheckCancel(betId string, currRoundId int64) bool {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if betId == BetIdx1 && mk.bet1 != nil && mk.bet1.RoundId == currRoundId && !mk.avBet1.CashOut && !mk.avBet1.Cancel {
		mk.avBet1.Cancel = true
		return true
	} else if betId == BetIdx2 && mk.bet2 != nil && mk.bet2.RoundId == currRoundId && !mk.avBet2.CashOut && !mk.avBet2.Cancel {
		mk.avBet2.Cancel = true
		return true
	}
	return false
}

// CheckCashOut 判断是否可以CashOut
func (mk *AviatorMarker) CheckCashOut(betId string, currRoundId int64) bool {
	mk.mu.Lock()
	defer mk.mu.Unlock()
	if betId == BetIdx1 && mk.bet1 != nil && mk.bet1.RoundId == currRoundId && !mk.avBet1.Cancel && !mk.avBet1.CashOut {
		mk.avBet1.CashOut = true
		return true
	} else if betId == BetIdx2 && mk.bet2 != nil && mk.bet2.RoundId == currRoundId && !mk.avBet2.Cancel && !mk.avBet2.CashOut {
		mk.avBet2.CashOut = true
		return true
	}
	return false
}
